#include "win32_thread.h"

#include "debug/logger.h"

#include <Windows.h>

namespace renderit
{
	namespace thread
	{
		struct thread_proc
		{
			void(*f)(void *);
			void * p;
		};

		static DWORD WINAPI ThreadProc(LPVOID lpParameter)
		{
			thread_proc * runner = reinterpret_cast<thread_proc*>(lpParameter);
			runner->f(runner->p);
			return 0;
		}

		HANDLE create_thread(void(*f)(void *), void * p)
		{
			thread_proc * proc = new thread_proc();
			proc->f = f;
			proc->p = p;
			DWORD threadid;
			HANDLE hthread = ::CreateThread(
				NULL,				// lpThreadAttributes
				0,					// dwStackSize
				ThreadProc,			// lpStartAddress
				proc,				// lpparameter
				CREATE_SUSPENDED,	// dwCreationFlags
				&threadid			// lpThreadId
			);

			::ResumeThread(hthread);

			return hthread;
		}

		bool wait_thread(HANDLE hthread)
		{
			DWORD r = ::WaitForSingleObject(hthread, INFINITE);
			switch (r)
			{
			case WAIT_ABANDONED:
				logger::warn("Wait For Thread Abandowned!");
				break;

			case WAIT_OBJECT_0:
				logger::warn("Wait For Thread Signaled!");
				break;

			case WAIT_TIMEOUT:
				logger::warn("Wait For Thread Timeout!");
				break;

			case WAIT_FAILED:
				logger::warn("Wait For Thread Failed!");
				break;
			}
			::CloseHandle(hthread);
			return true;
		}

		bool wait_threads(HANDLE * handers, uint32 count)
		{
			if (count > MAXIMUM_WAIT_OBJECTS)
			{
				return false;
			}
			
			DWORD r = ::WaitForMultipleObjects(count, handers, TRUE, INFINITE);
			
			logger::warn("Wait For Multi-Threads Result:%u", r);
			DWORD err = ::GetLastError();
			logger::warn("Wait For Multi-Threads Error:%u", err);
			
			for (uint32 i = 0; i < count; ++i)
			{
				::CloseHandle(handers[i]);
			}

			return true;
		}
	}
}